﻿<?xml version="1.0" encoding="UTF-8" ?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="text" encoding="utf-8"/>
  <xsl:template match="/">
    /*
    ===============================================================================================================================================
    ===== WARRNING: THE FOLLOWING CODE IS AUTO GENERATED, DO NOT MODIFY THIS CODE! EXTEND THIS CODE BY USING PARTIAL CLASSES AND SUB CLASSES. =====
    ===============================================================================================================================================
    */

    using System;
    using System.Collections.Concurrent;
    using System.Collections.Generic;
    using System.Linq;
    using System.Runtime.Serialization;
    using System.ServiceModel;
    using System.Threading;
    using Microsoft.VisualStudio.TestTools.UnitTesting;
    using System.Threading.Tasks;
    <xsl:for-each select="contract/service">
      namespace <xsl:value-of select="@clrNamespace"/>
      {
      using Messages;
      using Faults;
      using Interfaces;
      using Services;
      using Aspects;<xsl:if test="@extends">
        using <xsl:value-of select="../service[@name=current()/@extends]/@clrNamespace"/>.Messages ;
        using <xsl:value-of select="../service[@name=current()/@extends]/@clrNamespace"/>.Faults;
        using <xsl:value-of select="../service[@name=current()/@extends]/@clrNamespace"/>.Interfaces;
        using <xsl:value-of select="../service[@name=current()/@extends]/@clrNamespace"/>.Services;
      </xsl:if>

      public static class Namespaces
      {
      public const string XmlService = "<xsl:value-of select="@xmlNamespace"/>";
      public const string XmlSchema = "<xsl:value-of select="@xmlNamespace"/>#data";
      public const string ClrRoot = "<xsl:value-of select="@clrNamespace"/>";
      public const string ClrModels = ClrRoot + ".Models";
      public const string ClrMessages = ClrRoot + ".Messages";
      }

      namespace Messages
      {

      [DataContract(Name="<xsl:value-of select="@name"/>Request", Namespace=Namespaces.XmlSchema)]
      public partial class <xsl:value-of select="@name"/>Request <xsl:if test="@extends">
        : <xsl:value-of select="../service[@name=current()/@extends]/@name"/>Request
      </xsl:if>
      { }

      [DataContract(Name="Batch<xsl:value-of select="@name"/>Request", Namespace=Namespaces.XmlSchema)]
      public partial class Batch<xsl:value-of select="@name"/>Request
      {

      [DataMember(Name="DegreeOfParallelism", IsRequired = false)]
      public int DegreeOfParallelism {get;set;}

      [DataMember(Name="Requests", IsRequired=true)]
      public IDictionary&lt;string, <xsl:value-of select="@name"/>Request&gt; Requests { get; set; }
      }

      <xsl:for-each select="operations/operation">
        [DataContract(Name="<xsl:value-of select="@name"/>Request", Namespace=Namespaces.XmlSchema)]
        public partial class <xsl:value-of select="@name"/>Request : <xsl:value-of select="../../@name"/>Request { }
      </xsl:for-each>

      [DataContract(Name="<xsl:value-of select="@name"/>Response", Namespace=Namespaces.XmlSchema)]
      public partial class <xsl:value-of select="@name"/>Response  <xsl:if test="@extends">
        : <xsl:value-of select="../service[@name=current()/@extends]/@name"/>Response
      </xsl:if>
      { }

      [DataContract(Name="Batch<xsl:value-of select="@name"/>Response", Namespace=Namespaces.XmlSchema)]
      public partial class Batch<xsl:value-of select="@name"/>Response
      {
      [DataMember(Name="Responses", IsRequired=true)]
      public IDictionary&lt;string, <xsl:value-of select="@name"/>Response&gt; Responses { get; set; }

      [DataMember(Name="Faults", IsRequired=true)]
      public IDictionary&lt;string, <xsl:value-of select="@name"/>Fault&gt; Faults { get; set; }
      }

      <xsl:for-each select="operations/operation">
        [DataContract(Name="<xsl:value-of select="@name"/>Response", Namespace=Namespaces.XmlSchema)]
        public partial class <xsl:value-of select="@name"/>Response : <xsl:value-of select="../../@name"/>Response { }
      </xsl:for-each>
      }

      namespace Faults
      {
      [DataContract(Name="<xsl:value-of select="@name"/>Fault", Namespace=Namespaces.XmlSchema)]
      public partial class <xsl:value-of select="@name"/>Fault <xsl:if test="@extends">
        : <xsl:value-of select="../service[@name=current()/@extends]/@name"/>Fault
      </xsl:if>
      { }

      <xsl:for-each select="operations/operation">
        [DataContract(Name="<xsl:value-of select="@name"/>Fault", Namespace=Namespaces.XmlSchema)]
        public partial class <xsl:value-of select="@name"/>Fault : <xsl:value-of select="../../@name"/>Fault { }
      </xsl:for-each>
      }

      namespace Interfaces
      {
        <xsl:if test="@description">
          /// &lt;summary&gt;
          /// <xsl:value-of select="@description"/>
          /// &lt;/summary&gt;
        </xsl:if>
        [ServiceContract(Name="<xsl:value-of select="@name"/>", Namespace=Namespaces.XmlService)]
        public partial interface I<xsl:value-of select="@name"/> <xsl:if test="@extends">
          : I<xsl:value-of select="../service[@name=current()/@extends]/@name"/>
        </xsl:if>
        {
        <xsl:for-each select="operations/operation">
          <xsl:if test="@description">
            /// &lt;summary&gt;
            /// <xsl:value-of select="@description"/>
            /// &lt;/summary&gt;
          </xsl:if>
          [FaultContract(typeof(<xsl:value-of select="@name"/>Fault))]
          [OperationContract(Name="<xsl:value-of select="@name"/>")]
          <xsl:value-of select="@name"/>Response <xsl:value-of select="@name"/>(<xsl:value-of select="@name"/>Request request);
        </xsl:for-each>
        }

        [ServiceContract(Name="Batch<xsl:value-of select="@name"/>", Namespace=Namespaces.XmlService)]
        public partial interface IBatch<xsl:value-of select="@name"/>
        {
        [FaultContract(typeof(<xsl:value-of select="@name"/>Fault))]
        [OperationContract(Name="Process")]
        Batch<xsl:value-of select="@name"/>Response Process(Batch<xsl:value-of select="@name"/>Request request);
        }
        
        public partial interface I<xsl:value-of select="@name"/>Client
        {
          I<xsl:value-of select="@name"/> Service { get; set; }
        }
      }

      namespace Tests
      {
      <xsl:for-each select="operations/operation">
        [TestClass]
        public partial class <xsl:value-of select="@name"/>Test
        {
        private <xsl:value-of select="@name"/>Request request;
        private <xsl:value-of select="@name"/>Response response;
        private I<xsl:value-of select="../../@name"/> service;

        [TestInitialize]
        public void TestInitialize()
        {
        request = new <xsl:value-of select="@name"/>Request();
        service = new Mock<xsl:value-of select="../../@name"/>();
        response = service.<xsl:value-of select="@name"/>(request);
        }
        
        [TestMethod]
        public void ResponseIsNotNull()
        {
        Assert.IsNotNull(response);
        }

        [TestMethod]
        public void ResponseTypeIs<xsl:value-of select="@name"/>Response()
        {
        Assert.IsInstanceOfType(response, typeof(<xsl:value-of select="@name"/>Response));
        }

        }
      </xsl:for-each>
      }

      namespace Aspects
      {
        [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
        public abstract class <xsl:value-of select="@name"/>Aspect : Attribute
      {
      public int Order { get; set; }
      protected <xsl:value-of select="@name"/>Aspect() : this(-100) { }
      protected <xsl:value-of select="@name"/>Aspect(int order) { Order = order; }
          public virtual void OnPre<xsl:value-of select="@name"/>Operation(ref <xsl:value-of select="@name"/>Request request) { }
          public virtual void OnPost<xsl:value-of select="@name"/>Operation(ref <xsl:value-of select="@name"/>Request request, ref <xsl:value-of select="@name"/>Response response) { }
          public virtual void On<xsl:value-of select="@name"/>OperationError(ref <xsl:value-of select="@name"/>Request request, ref Exception exception) { }
        } 
      }

      namespace Services
      {

      /*

      For .svc file:

      &lt;%@ ServiceHost Language="C#" Debug="true" Service="<xsl:value-of select="@clrNamespace"/>.Services.Mock<xsl:value-of select="@name"/>" %&gt;

      For web.config, serviceModel section:

      &lt;service name="<xsl:value-of select="@clrNamespace"/>.Services.Mock<xsl:value-of select="@name"/>"&gt;
      &lt;endpoint bindingNamespace="<xsl:value-of select="@xmlNamespace"/>"
      binding="basicHttpBinding"
      contract="<xsl:value-of select="@clrNamespace"/>.Interfaces.I<xsl:value-of select="@name"/>"/&gt;
      &lt;/service&gt;
      */

      [ServiceBehavior(Name = "<xsl:value-of select="@name"/>", Namespace = Namespaces.XmlService)]
      public partial class Mock<xsl:value-of select="@name"/> : <xsl:value-of select="@name"/>Base
      {
      <xsl:for-each select="operations/operation">
        public override <xsl:value-of select="@name"/>Response <xsl:value-of select="@name"/>(<xsl:value-of select="@name"/>Request request) { 
          // simulate some latency (up to 5 seconds).
          Thread.Sleep(new Random(DateTime.UtcNow.Millisecond).Next(5000));
          if (request == null)
            throw new FaultException&lt;<xsl:value-of select="@name"/>Fault&gt;(new <xsl:value-of select="@name"/>Fault(), "Request was null.");
          return new <xsl:value-of select="@name"/>Response(); }
      </xsl:for-each>
      <xsl:if test="@extends">
        <xsl:for-each select="../service[@name=current()/@extends]/operations/operation">
          public override <xsl:value-of select="@name"/>Response <xsl:value-of select="@name"/>(<xsl:value-of select="@name"/>Request request)
          {
          if (request == null)
          throw new FaultException&lt;<xsl:value-of select="@name"/>Fault&gt;(new <xsl:value-of select="@name"/>Fault(), "Request was null.");
          return new <xsl:value-of select="@name"/>Response();
          }
        </xsl:for-each>
      </xsl:if>
      }
      public abstract partial class <xsl:value-of select="@name"/>Base : <xsl:if test="@extends">
        <xsl:value-of select="../service[@name=current()/@extends]/@name"/>Base,
      </xsl:if>I<xsl:value-of select="@name"/>
      {
      #region Section for dealing with aspects.
      private IList&lt;<xsl:value-of select="@name"/>Aspect&gt;   aspects = null;
      internal IEnumerable&lt;<xsl:value-of select="@name"/>Aspect&gt;
      Aspects
      {
        get {
          if (aspects == null)
          {
            aspects = new List&lt;<xsl:value-of select="@name"/>Aspect&gt;();
            foreach (var aspect in GetType().GetCustomAttributes(typeof(<xsl:value-of select="@name"/>Aspect), true))
            aspects.Add((aspect as <xsl:value-of select="@name"/>Aspect));
          }
          return aspects.OrderBy(a=>a.Order).ToList(); 
        }
      }
      #endregion
      public event <xsl:value-of select="@name"/>RequestHandler Pre<xsl:value-of select="@name"/>Operation;
      public event <xsl:value-of select="@name"/>ResponseHandler Post<xsl:value-of select="@name"/>Operation;
      public event <xsl:value-of select="@name"/>ErrorHandler <xsl:value-of select="@name"/>OperationError;
      <xsl:for-each select="operations/operation">
        public event <xsl:value-of select="@name"/>RequestHandler Pre<xsl:value-of select="@name"/>;
        public event <xsl:value-of select="@name"/>ResponseHandler Post<xsl:value-of select="@name"/>;
        public event <xsl:value-of select="@name"/>ErrorHandler <xsl:value-of select="@name"/>Error;
      </xsl:for-each>
      public delegate void <xsl:value-of select="@name"/>RequestHandler(ref <xsl:value-of select="@name"/>Request request);
      public delegate void <xsl:value-of select="@name"/>ResponseHandler(ref <xsl:value-of select="@name"/>Request request, ref <xsl:value-of select="@name"/>Response response);
      public delegate void <xsl:value-of select="@name"/>ErrorHandler(ref <xsl:value-of select="@name"/>Request request, ref Exception exception);
      <xsl:for-each select="operations/operation">
        public delegate void <xsl:value-of select="@name"/>RequestHandler(ref <xsl:value-of select="@name"/>Request request);
        public delegate void <xsl:value-of select="@name"/>ResponseHandler(ref <xsl:value-of select="@name"/>Request request, ref <xsl:value-of select="@name"/>Response response);
        public delegate void <xsl:value-of select="@name"/>ErrorHandler(ref <xsl:value-of select="@name"/>Request request, ref Exception exception);
      </xsl:for-each>
      
      protected void RaisePre<xsl:value-of select="@name"/>Operation(<xsl:value-of select="@name"/>Request request) {        
        <xsl:if test="@extends">RaisePre<xsl:value-of select="../service[@name=current()/@extends]/@name"/>Operation(request);</xsl:if>        
        foreach (var aspect in Aspects)
          aspect.OnPre<xsl:value-of select="@name"/>Operation(ref request);
        if (Pre<xsl:value-of select="@name"/>Operation != null) Pre<xsl:value-of select="@name"/>Operation(ref request); }
      
      protected void RaisePost<xsl:value-of select="@name"/>Operation(<xsl:value-of select="@name"/>Request request, <xsl:value-of select="@name"/>Response response) {
        
        foreach (var aspect in Aspects)
          aspect.OnPost<xsl:value-of select="@name"/>Operation(ref request, ref response);
        if (Post<xsl:value-of select="@name"/>Operation != null) Post<xsl:value-of select="@name"/>Operation(ref request, ref response); 
        
        <xsl:if test="@extends">RaisePost<xsl:value-of select="../service[@name=current()/@extends]/@name"/>Operation(request, response);</xsl:if>  
        }
      
      protected void Raise<xsl:value-of select="@name"/>OperationError(<xsl:value-of select="@name"/>Request request, Exception exception) {
        <xsl:if test="@extends">Raise<xsl:value-of select="../service[@name=current()/@extends]/@name"/>OperationError(request, exception);</xsl:if>

      foreach (var aspect in Aspects)
        aspect.On<xsl:value-of select="@name"/>OperationError(ref request, ref exception);

      if (<xsl:value-of select="@name"/>OperationError != null) 
         <xsl:value-of select="@name"/>OperationError(ref request, ref exception);
      
      }
      
      <xsl:for-each select="operations/operation">
      protected void RaisePre<xsl:value-of select="@name"/>(<xsl:value-of select="@name"/>Request request) {
        RaisePre<xsl:value-of select="../../@name"/>Operation(request);
        if (Pre<xsl:value-of select="@name"/> != null) Pre<xsl:value-of select="@name"/>(ref request); }
      
      protected void RaisePost<xsl:value-of select="@name"/>(<xsl:value-of select="@name"/>Request request, <xsl:value-of select="@name"/>Response response) {
        if (Post<xsl:value-of select="@name"/> != null) Post<xsl:value-of select="@name"/>(ref request, ref response);
        RaisePost<xsl:value-of select="../../@name"/>Operation(request, response);}
      
      protected void Raise<xsl:value-of select="@name"/>Error(<xsl:value-of select="@name"/>Request request, Exception exception) {
        Raise<xsl:value-of select="../../@name"/>OperationError(request, exception);
        if (<xsl:value-of select="@name"/>Error != null) <xsl:value-of select="@name"/>Error(ref request, ref exception); }
        
      </xsl:for-each>
      <xsl:for-each select="operations/operation">
      public abstract <xsl:value-of select="@name"/>Response <xsl:value-of select="@name"/>(<xsl:value-of select="@name"/>Request request);
      </xsl:for-each>
      <xsl:for-each select="operations/operation">

      <xsl:value-of select="@name"/>Response  I<xsl:value-of select="../../@name"/>.<xsl:value-of select="@name"/>(<xsl:value-of select="@name"/>Request request) 
      {
        <xsl:value-of select="@name"/>Response response = null;
        try 
        {
          RaisePre<xsl:value-of select="@name"/>(request);          
          response = <xsl:value-of select="@name"/>(request);          
          RaisePost<xsl:value-of select="@name"/>(request, response);          
          return response;  
        }
        catch (Exception exception) 
        {
          Raise<xsl:value-of select="@name"/>Error(request, exception);       
        }
        return response; 
      }
      
      </xsl:for-each> 
    }
      
      <xsl:if test="operations">
        public class Batch<xsl:value-of select="@name"/> : IBatch<xsl:value-of select="@name"/>
        {
        private readonly I<xsl:value-of select="@name"/> service;
        private readonly int maxDegreeOfParallelism;
        public Batch<xsl:value-of select="@name"/>(I<xsl:value-of select="@name"/> service, int maxDegreeOfParallelism = 10) {
        this.service = service;
        this.maxDegreeOfParallelism = maxDegreeOfParallelism; }

        public Batch<xsl:value-of select="@name"/>Response Process(Batch<xsl:value-of select="@name"/>Request request) {

        if ((request.DegreeOfParallelism &lt;= 0) || (request.DegreeOfParallelism &gt; maxDegreeOfParallelism))
            request.DegreeOfParallelism = maxDegreeOfParallelism;

        var response = new Batch<xsl:value-of select="@name"/>Response {
         Responses = new ConcurrentDictionary&lt;string, <xsl:value-of select="@name"/>Response&gt;(),
         Faults = new ConcurrentDictionary&lt;string, <xsl:value-of select="@name"/>Fault&gt;() };
        
          Parallel.ForEach(
            request.Requests, 
                new ParallelOptions {
                  MaxDegreeOfParallelism = request.DegreeOfParallelism 
                },
          
            keyValuePair => {     
              try
              {
              <xsl:for-each select="operations/operation">
                if (keyValuePair.Value is <xsl:value-of select="@name"/>Request)
                response.Responses.Add(keyValuePair.Key, service.<xsl:value-of select="@name"/>(keyValuePair.Value as <xsl:value-of select="@name"/>Request));
              </xsl:for-each>
              }
              catch(FaultException&lt;<xsl:value-of select="@name"/>Fault&gt; fault)
              {
              <xsl:for-each select="operations/operation">
                if (fault.Detail is <xsl:value-of select="@name"/>Fault)
                response.Faults.Add(keyValuePair.Key, fault.Detail as <xsl:value-of select="@name"/>Fault);
              </xsl:for-each>
              } 
            }
            );
        
            return response; 
       }
     }
    </xsl:if>

      public partial class <xsl:value-of select="@name"/>Proxy : ClientBase&lt;I<xsl:value-of select="@name"/>&gt;, I<xsl:value-of select="@name"/>
      {          
      <xsl:for-each select="operations/operation">
        public <xsl:value-of select="@name"/>Response <xsl:value-of select="@name"/>(<xsl:value-of select="@name"/>Request request)
        {
        return Channel.<xsl:value-of select="@name"/>(request);
        }
      </xsl:for-each>
      <xsl:if test="@extends">
        <xsl:for-each select="../service[@name=current()/@extends]/operations/operation">
          public <xsl:value-of select="@name"/>Response <xsl:value-of select="@name"/>(<xsl:value-of select="@name"/>Request request)
          {
          return Channel.<xsl:value-of select="@name"/>(request);
          }
        </xsl:for-each>
      </xsl:if>
      }

      public class Batch<xsl:value-of select="@name"/>Proxy : ClientBase&lt;IBatch<xsl:value-of select="@name"/>&gt;, IBatch<xsl:value-of select="@name"/>
        {
        <xsl:for-each select="operations/operation">
          public delegate void <xsl:value-of select="@name"/>ResponseHandler(<xsl:value-of select="@name"/>Request request, <xsl:value-of select="@name"/>Response response);
          public delegate void <xsl:value-of select="@name"/>FaultHandler(<xsl:value-of select="@name"/>Request request, <xsl:value-of select="@name"/>Fault fault);
          public event <xsl:value-of select="@name"/>ResponseHandler <xsl:value-of select="@name"/>Response;
          public event <xsl:value-of select="@name"/>FaultHandler <xsl:value-of select="@name"/>Fault;
        </xsl:for-each>

        public Batch<xsl:value-of select="@name"/>Response Process(Batch<xsl:value-of select="@name"/>Request request) { return Channel.Process(request); }

        public void Process(IList&lt;<xsl:value-of select="@name"/>Request&gt; requests) { ThreadPool.QueueUserWorkItem(Process, requests); }

        public void Process(object obj)
        {
        var requests = obj as IList&lt;<xsl:value-of select="@name"/>Request&gt;;
        IDictionary&lt;<xsl:value-of select="@name"/>Request, <xsl:value-of select="@name"/>Response&gt; responses;
        IDictionary&lt;<xsl:value-of select="@name"/>Request, <xsl:value-of select="@name"/>Fault&gt; faults;
        Process(requests, out responses, out faults);
        foreach (var item in responses) {
        <xsl:for-each select="operations/operation">
          if (item.Key is <xsl:value-of select="@name"/>Request)
          <xsl:value-of select="@name"/>Response(item.Key as <xsl:value-of select="@name"/>Request, item.Value as <xsl:value-of select="@name"/>Response);
        </xsl:for-each> }

        foreach (var item in faults) {
        <xsl:for-each select="operations/operation">
          if (item.Key is <xsl:value-of select="@name"/>Request)
          <xsl:value-of select="@name"/>Fault(item.Key as <xsl:value-of select="@name"/>Request, item.Value as <xsl:value-of select="@name"/>Fault);
        </xsl:for-each> }
        }

        public void Process(
        IList&lt;<xsl:value-of select="@name"/>Request&gt; requests,
        out IDictionary&lt;<xsl:value-of select="@name"/>Request, <xsl:value-of select="@name"/>Response&gt; responses,
        out IDictionary&lt;<xsl:value-of select="@name"/>Request, <xsl:value-of select="@name"/>Fault&gt; faults )
        {
        var requestDictionary = requests.ToDictionary(request => Guid.NewGuid().ToString());
        var processResponse = Process(new Batch<xsl:value-of select="@name"/>Request
        {
        Requests = requestDictionary
        });
        responses = (from resp in processResponse.Responses
        join req in requestDictionary
        on resp.Key equals req.Key
        select new { Request = req.Value, Response = resp.Value })
        .ToDictionary(k => k.Request, v => v.Response);

        faults = (from fault in processResponse.Faults
        join req in requestDictionary
        on fault.Key equals req.Key
        select new { Request = req.Value, Fault = fault.Value })
        .ToDictionary(k => k.Request, v => v.Fault);
        }
        }

      }

      namespace Clients
      {
      public partial class <xsl:value-of select="@name"/>Client : I<xsl:value-of select="@name"/>Client
        {
          public <xsl:value-of select="@name"/>Client(I<xsl:value-of select="@name"/> service) { Service = service; }
          public I<xsl:value-of select="@name"/> Service { get; set; }
        }
    }
  }
    </xsl:for-each>
    <xsl:apply-templates/>
  </xsl:template>
</xsl:stylesheet>